package com.example.springbootvue.controller;

import com.example.springbootvue.entity.User;
import com.example.springbootvue.security.JwtTokenProvider;
import com.example.springbootvue.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.HashMap;
import java.util.Map;

/**
 * 认证控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/auth")
@RequiredArgsConstructor
public class AuthController {

    private final UserService userService;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenProvider tokenProvider;

    /**
     * 用户注册
     */
    @PostMapping("/register")
    public ResponseEntity<?> registerUser(@Valid @RequestBody User user) {
        log.info("尝试注册用户: {}", user.getUsername());

        // 检查用户名是否已存在
        if (userService.existsByUsername(user.getUsername())) {
            log.warn("用户名 {} 已被使用", user.getUsername());
            return new ResponseEntity<>(Map.of("message", "用户名已被使用！"),
                    HttpStatus.BAD_REQUEST);
        }

        // 检查邮箱是否已存在
        if (userService.existsByEmail(user.getEmail())) {
            log.warn("邮箱 {} 已被使用", user.getEmail());
            return new ResponseEntity<>(Map.of("message", "邮箱已被使用！"),
                    HttpStatus.BAD_REQUEST);
        }

        // 创建新用户
        User newUser = new User();
        newUser.setUsername(user.getUsername());
        String encodedPassword = passwordEncoder.encode(user.getPassword());
        log.info("密码加密结果: {} (MD5)", encodedPassword);
        newUser.setPassword(encodedPassword);
        newUser.setEmail(user.getEmail());
        newUser.setPhone(user.getPhone());
        newUser.setStatus(1); // 默认正常状态

        userService.save(newUser);

        log.info("用户注册成功: {}", user.getUsername());
        return new ResponseEntity<>(Map.of("message", "用户注册成功！"), HttpStatus.CREATED);
    }

    /**
     * 用户登录
     */
    @PostMapping("/login")
    public ResponseEntity<?> authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {
        log.info("尝试认证用户: {}", loginRequest.getUsernameOrEmail());

        try {
            // 查找用户
            User user = userService.findByUsername(loginRequest.getUsernameOrEmail());
            if (user == null) {
                user = userService.findByEmail(loginRequest.getUsernameOrEmail());
            }

            if (user == null) {
                log.warn("用户不存在: {}", loginRequest.getUsernameOrEmail());
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                        .body(Map.of("message", "用户名或密码错误"));
            }

            // 验证密码
            log.info("验证密码 - 用户: {}, 密码长度: {}, 存储的密码哈希: {}",
                    user.getUsername(),
                    loginRequest.getPassword() != null ? loginRequest.getPassword().length() : 0,
                    user.getPassword());

            boolean passwordMatches = passwordEncoder.matches(loginRequest.getPassword(), user.getPassword());
            log.info("密码验证结果: {}", passwordMatches ? "匹配" : "不匹配");

            // 如果使用MD5验证失败，尝试直接比较明文密码的MD5哈希值
            if (!passwordMatches) {
                log.warn("密码验证失败: {}", user.getUsername());
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                        .body(Map.of("message", "用户名或密码错误"));
            }

            // 生成JWT令牌
            String jwt = tokenProvider.generateToken(user.getUsername());
            log.info("用户认证成功: {}", user.getUsername());

            Map<String, Object> response = new HashMap<>();
            response.put("accessToken", jwt);
            response.put("tokenType", "Bearer");
            response.put("username", user.getUsername());
            response.put("email", user.getEmail());
            response.put("status", user.getStatus());

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("用户认证失败: {}, 原因: {}", loginRequest.getUsernameOrEmail(), e.getMessage(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("message", "认证过程发生错误"));
        }
    }

    /**
     * 检查用户名是否可用
     */
    @GetMapping("/checkUsernameAvailability")
    public ResponseEntity<?> checkUsernameAvailability(@RequestParam(value = "username") String username) {
        Boolean isAvailable = !userService.existsByUsername(username);
        return ResponseEntity.ok(new UserIdentityAvailability(isAvailable));
    }

    /**
     * 检查邮箱是否可用
     */
    @GetMapping("/checkEmailAvailability")
    public ResponseEntity<?> checkEmailAvailability(@RequestParam(value = "email") String email) {
        Boolean isAvailable = !userService.existsByEmail(email);
        return ResponseEntity.ok(new UserIdentityAvailability(isAvailable));
    }

    /**
     * 获取当前密码的MD5值（用于测试）
     */
    @GetMapping("/md5")
    public ResponseEntity<?> getMd5Password(@RequestParam(value = "password") String password) {
        String md5Password = passwordEncoder.encode(password);
        return ResponseEntity.ok(Map.of(
                "password", password,
                "md5", md5Password));
    }

    /**
     * 登录请求类
     */
    public static class LoginRequest {
        private String usernameOrEmail;
        private String password;

        public String getUsernameOrEmail() {
            return usernameOrEmail;
        }

        public void setUsernameOrEmail(String usernameOrEmail) {
            this.usernameOrEmail = usernameOrEmail;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }

    /**
     * 用户标识可用性响应类
     */
    public static class UserIdentityAvailability {
        private Boolean available;

        public UserIdentityAvailability(Boolean available) {
            this.available = available;
        }

        public Boolean getAvailable() {
            return available;
        }

        public void setAvailable(Boolean available) {
            this.available = available;
        }
    }
}